
<template>
  <!-- text-sm/[30px] 表示文字小号，行高为 30px -->
  <div class="sticky top-[5.5rem] text-sm/[30px] w-full p-5 mb-3 bg-white border border-gray-200 rounded-lg dark:bg-gray-800 dark:border-gray-700">
    <!-- 目录标题 -->
    <h2 class="flex items-center mb-2 font-bold text-gray-900 uppercase dark:text-white">
      <!-- 目录图标 -->
      <svg t="1699441758495" class="icon w-3.5 h-3.5 mr-2" viewBox="0 0 1024 1024" version="1.1"
           xmlns="http://www.w3.org/2000/svg" p-id="4043" width="200" height="200">
        <path
            d="M857.6 25.6a76.8 76.8 0 0 1 76.8 76.8v819.2a76.8 76.8 0 0 1-76.8 76.8H166.4a76.8 76.8 0 0 1-76.8-76.8V102.4a76.8 76.8 0 0 1 76.8-76.8h691.2z m-102.4 678.4H473.6l-2.2528 0.064a38.4 38.4 0 0 0 0 76.672L473.6 780.8h281.6l2.2528-0.064a38.4 38.4 0 0 0 0-76.672L755.2 704z m0-230.4H473.6l-2.2528 0.064a38.4 38.4 0 0 0 0 76.672L473.6 550.4h281.6l2.2528-0.064a38.4 38.4 0 0 0 0-76.672L755.2 473.6z m0-230.4H473.6l-2.2528 0.064a38.4 38.4 0 0 0 0 76.672L473.6 320h281.6l2.2528-0.064a38.4 38.4 0 0 0 0-76.672L755.2 243.2z"
            fill="#6B57FE" p-id="4044"></path>
        <path
            d="M281.6 691.2a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z m0-230.4a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z m0-230.4a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z"
            fill="#FFBA00" p-id="4045"></path>
      </svg>
      文章目录
    </h2>
    <div class="toc-wrapper">
      <ul class="toc">
        <li v-for="(h2,index) in titles" :key="index">
          <span class="py-2 pl-5" @click="scrollToView(h2.offsetTop)" :class="[h2.index === activeHeadingIndex ?'active py-1 text-sky-600 border-1-2 border-sky-600 font-bold' :'text-gray-500 font-normal']">{{h2.text}}</span>
          <ul v-if="h2.children && h2.children.length >0">
            <li v-for="(h3,index) in h2.children" :key="index">
              <span class="py-2 pl-10" @click="scrollToView(h3.offsetTop)" :class="[h3.index === activeHeadingIndex ? 'active py-1 text-sky-600 border-l-2 border-sky-600 font-bold' : 'text-gray-500 font-normal']">{{h3.text}}</span>
            </li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</template>
<script setup>
 import {onMounted,ref,onBeforeUnmount} from "vue";
 const titles = ref([])

 function initTocData(container) {
   // 获取所有标题元素
   let levels = ['h2','h3']
   let headings = container.querySelectorAll(levels)
   console.log(headings)
   // 存放组装后的目录标题数据
   let titlesArr = []
   let index = 1
   headings.forEach(heading=>{
     // 获取标题级别 h2->级别2 h3->级别3
     let headingLevel = parseInt(heading.tagName.substring(1))
     let headingText = heading.innerText
     // 标题的位置（距离顶部的距离）
     let offsetTop = heading.offsetTop -95
     if(headingLevel === 2){
       titlesArr.push({
         id: index,
         level: headingLevel,
         text: headingText,
         offsetTop,
         children: []
       })
     } else {// h3
       // 获取父级标题
       let parentHeading = titlesArr[titlesArr.length-1]
       // 添加子级标题
       parentHeading.children.push({
         index,
         level: headingLevel,
         text: headingText,
         offsetTop
       })
     }
     // 索引自增
     index++
   })
   console.log(titlesArr)
   titles.value = titlesArr
 }

 onMounted(()=>{
   // 通过 .artilce-content 样式来获取父级 div
   const container = document.querySelector('.article-content')

   // 使用 MutationObserver 监视 DOM 的变化
   const observer = new MutationObserver(mutationsList=>{
     for (let mutaion of mutationsList){
       if(mutaion.type === 'childList'){
         //先清空目录缓存数据
         titles.value = []
         initTocData(container)

         //监听图片加载事件
         const  images = container.querySelectorAll('img')
         images.forEach(image=>{
           image.addEventListener('load',()=>{
             //重新初始化目录数据
             initTocData(container)
           })
         })

        //添加滚动事件监听
        window.addEventListener('scroll',handleContentScroll)

       }
     }
   })

   //配置监视子节点变化
   const config = {childList: true,subtree: true}
   observer.observe(container,config)
 })

 function scrollToView(offsetTop){
   window.scrollTo({
     top: offsetTop,
     behavior: 'smooth'
   })
 }

 //记录当前被选中的标题下标
 const activeHeadingIndex = ref(-1)

 // 处理内容滚动事件
 function handleContentScroll() {
   let scrollY = window.scrollY
   titles.value.forEach(title=>{
     let offsetTop = title.offsetTop
     // 如果当前位置大于等于标题位置，则标记选中，记录被选中标题的下标
     if(scrollY >= offsetTop){
       activeHeadingIndex.value = title.index
     }

     let children = title.children
      if(children && children.length >0){
        children.forEach(child=>{
          let offsetTop = child.offsetTop
          if(scrollY >= offsetTop){
            activeHeadingIndex.value = child.index
          }
        })
      }
   })

 }

 onBeforeUnmount(()=>{
   window.removeEventListener('scroll',handleContentScroll)
 })
</script>

<style scoped>
::v-deep(.toc-wrapper) {
  position: relative;
  overflow-x: hidden;
  overflow-y: auto;
  max-height: 75vh;
  text-overflow: ellipsis;
  white-space: nowrap;
  scroll-behavior: smooth;
}

::v-deep(.toc:before) {
  content: " ";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: -1;
  width: 2px;
  background: #eaecef;
}
</style>